/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_socket.h"

static 	int 	_gTraceLvl_Sock = TRACELVL_WARNING;

int 	SSock_SetTraceLvl(int lvl)
{
	int 	ret = -1;
	
	switch(lvl){
		case TRACELVL_FATAL:
		case TRACELVL_ERROR:
		case TRACELVL_WARNING:
		case TRACELVL_NORMAL:
		case TRACELVL_DEBUG:
		case TRACELVL_ALL:
			_gTraceLvl_Sock = lvl;
			ret = 0;
			break;
		default:
			break;
	}

	return ret;
}

int 	SSock_GetTraceLvl(void)
{
	return  _gTraceLvl_Sock;
}


#define S_SOCKET_ADD2EPOLL(vHandle, vEvent, vUser, vFlag, vRet)	\
do{ \
	vRet 			= _E_SUCC;\
	vEvent.events 	= (vFlag);\
	vEvent.data.ptr = (void*)(vUser);\
	if (epoll_ctl(vHandle, EPOLL_CTL_ADD, (vUser)->fd, &vEvent) < 0) {\
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll CTL Add Fail: %d - %d\n", (vUser)->fd, errno);\
		vRet = _E_FAIL;\
	}\
}while(0)

#define S_SOCKET_DEL4EPOLL(vHandle, vUser, vRet)	\
do{ \
	vRet 			= _E_SUCC;\
	if (epoll_ctl(vHandle, EPOLL_CTL_DEL, (vUser)->fd, NULL) < 0) {\
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll CTL Del Fail: %d - %d\n", (vUser)->fd, errno);\
		vRet = _E_FAIL;\
	}\
}while(0)

#define S_SOCKET_MOD4EPOLL(vHandle, vEvent, vUser, vFlag, vRet)	\
do{ \
	vRet 			= _E_SUCC;\
	vEvent.events 	= (vFlag);\
	vEvent.data.ptr = (void*)(vUser);\
	if (epoll_ctl(vHandle, EPOLL_CTL_MOD, (vUser)->fd, &vEvent) < 0) {\
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll CTL Mod Fail:%d - %d\n", (vUser)->fd, errno);\
		vRet = _E_FAIL;\
	}\
}while(0)
	
/* --------------------------------------------------------
** Event Select 
*/

void 	EvSel_Init(_t_sysEvSel * pEvSel)
{
	_t_sysEvAio 	aioHandle = -1;

	/* Dispatch & EPoll Handle */
	aioHandle= epoll_create(S_EVSEL_MAX);
	if(aioHandle == -1){
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll Create Fail\n");
	}
	pEvSel->aioHandle = aioHandle;
	SYS_INIT_CS(&(pEvSel->lock));
	return;
}

void * 	EvSel_Exec(_t_sysEvSel * pEvSel)
{	
	int 			i, count, aioCnt, op;
	int 	(* 		callback)();
	
	/* EPoll */
	_t_sysEvAio 			aioHandle;
	_t_sockEvUser 		* 	pUser;
	_t_sockEvCb 		* 	pCb;
	struct 	epoll_event *	pEvPoll;
	struct 	epoll_event 	evAU[S_EVSEL_MAX];

	STask_SetName("EvSel");
	aioHandle = pEvSel->aioHandle;
	if(aioHandle == -1){
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll Create Fail\n");
		return NULL;
	}
	aioCnt 	= S_EVSEL_MAX;
	while(1){
    	count = epoll_wait(aioHandle, evAU, aioCnt, S_EVSEL_TO);

   		for (i = 0, pEvPoll = evAU; i < count; i++, pEvPoll++) {
			callback= NULL;
			op 		= 0X0;
			pUser 	= (_t_sockEvUser *)(pEvPoll->data.ptr);
			if(pUser &&  (pCb = pUser->pCb)){
				callback= pCb->cbDisp;
			}
			
			/* Process Err */
			if(pEvPoll->events & (EPOLLERR|EPOLLHUP|EPOLLRDHUP)){
				op = S_EVOP_ERR;
			}
			/* Process IN */
			else if(pEvPoll->events & EPOLLIN){
				op = S_EVOP_RX;
			}
			/* Process Out */
			else if(pEvPoll->events & EPOLLOUT){
				op = S_EVOP_TX;
			}
			
			if(callback){
 				callback(pUser, op, 0);
			}
			continue;
			
		}
	}
	
	return NULL;
}

/* EPOLLRDHUP */
sInt32 	EvSel_Add(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
 	struct 	epoll_event 	ev;
	int 	ret, i;

	ret = -1;
	if(pEvSel && pEvUser){
		SYS_ENTER_CS(&(pEvSel->lock));
		i = 0;
		do{
			S_SOCKET_ADD2EPOLL(pEvSel->aioHandle, ev, pEvUser, 
							(pEvUser->eCase),
							ret);
			i+=1;
		}while((ret == -1) && (i<2));
		SYS_LEAVE_CS(&(pEvSel->lock));
	}
	return ret;
}

sInt32 	EvSel_Del(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
	int 	ret, i;

	ret = -1;
	if(pEvSel && pEvUser){
		SYS_ENTER_CS(&(pEvSel->lock));
		i = 0;
		do{
			S_SOCKET_DEL4EPOLL(pEvSel->aioHandle, pEvUser, ret);
			i+=1;
		}while((ret == -1) && (i<2));
		SYS_LEAVE_CS(&(pEvSel->lock));
	}
	return ret;
}

sInt32 	EvSel_Mod(_t_sysEvSel * pEvSel, _t_sockEvUser * pEvUser)
{
 	struct 	epoll_event 	ev;
	int 	ret, i;

	ret = -1;
	if(pEvSel && pEvUser){
		SYS_ENTER_CS(&(pEvSel->lock));
		i = 0;
		do{
			S_SOCKET_MOD4EPOLL(pEvSel->aioHandle, ev, pEvUser, 
								(pEvUser->eCase),
								ret);
			i+=1;
		}while((ret == -1) && (i<2));
		if(ret == -1){
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "EPoll CTL Mod ?\n");
		}
		SYS_LEAVE_CS(&(pEvSel->lock));
	}
	return ret;
}

/* -----------------------------------------------------------------------
**	UDP Socket 1
**	Send.
**	Receive 1: Wait till Data Arrive.
**	Receive 2: Wait till Timeout.
**	
*/
#define SYS_UDP_RE_WR 		0X5		/* Write Delay Cnt */
#define SYS_UDP_TO_WR 		0X1		/* Write Delay Time */
#define SYS_UDP_BUF_MAX 	0X10000


int 	SockTx_UdpSg(int 				sockId, 				
					_t_sgbuf 		* 		sgBuf,
					int 					sgCnt,
					S_SOCKET_ADDRIN *		pSockAddr)
{
	int 				ret, retry, flag;
	struct msghdr 		ioHead;

	if((!pSockAddr) || (!sgBuf) || (sgCnt <= 0) || (sockId == -1)){
		return -1;
	}

	/* IoVec */

	/* IoHead */
	ioHead.msg_flags 	= 0; 		
	ioHead.msg_control 	= NULL;		
	ioHead.msg_controllen= 0;		
	ioHead.msg_iov 		= sgBuf;	
	ioHead.msg_iovlen 	= sgCnt;	
	ioHead.msg_name 	= pSockAddr;
	ioHead.msg_namelen 	= sizeof(S_SOCKET_ADDRIN);	

	retry	= 0;
	do{
		flag 	= 0;
		ret 	= sendmsg(sockId, &ioHead, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_UDP_RE_WR){
						retry++;
						SYS_SLEEP(SYS_UDP_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockSend Udp:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}


int 	SockTx_Udp(int 				sockId, 				
					unsigned char 	* 	pMsg, 	
					int 				msgLen,
					S_SOCKET_ADDRIN*	pSockAddr)
{
	int 				ret, retry, flag;
	struct msghdr 		ioHead;
	struct iovec  		ioVec[1];

	if((!pSockAddr) || (!pMsg) || (msgLen <= 0) || (sockId == -1)){
		return -1;
	}

	/* IoVec */
	ioVec[0].iov_base 	= pMsg;
	ioVec[0].iov_len 	= msgLen;

	/* IoHead */
	ioHead.msg_flags 	= 0; 		
	ioHead.msg_control 	= NULL;		
	ioHead.msg_controllen= 0;		
	ioHead.msg_iov 		= ioVec;	
	ioHead.msg_iovlen 	= 1;	
	ioHead.msg_name 	= pSockAddr;
	ioHead.msg_namelen 	= sizeof(S_SOCKET_ADDRIN);	

	retry	= 0;
	do{
		flag 	= 0;
		ret 	= sendmsg(sockId, &ioHead, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_UDP_RE_WR){
						retry++;
						SYS_SLEEP(SYS_UDP_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockSend Udp:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockSend Udp:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}


int 	SockRx_Udp(int 			sockId, 
					_t_cbentry * 	pCbEntry)
{
	int 				ret, flag;
	socklen_t			vSockLen;
	S_SOCKET_ADDRIN	vSockAddr;

	unsigned char 		vBuf[SYS_UDP_BUF_MAX];

	if(sockId == -1){
		return -1;
	}

	/* Let's Consume all the Data First */
	flag = 1;
	while(flag == 1){
		#if 0
		SYS_MEMZERO(&vSockAddr, sizeof(vSockAddr));
		#endif
		vSockLen = sizeof(S_SOCKET_ADDRIN);	
		ret=recvfrom(sockId, vBuf, SYS_UDP_BUF_MAX, 0, 
					(struct  sockaddr *)(&vSockAddr), &vSockLen);
		if (ret > 0) {
			/* Data read from the socket */
			if(pCbEntry && (pCbEntry->cbProc)){
				if(pCbEntry->cbProc(pCbEntry->pArg, 
									pCbEntry->lArg, 
									vBuf, ret,
									&vSockAddr) == -1){
					/* We Recv the Left*/
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, "SockRecv Udp:[%d] CallBack Fail!\n", 
						sockId);
				}
			}
			continue;
		}
		else if (ret == -1) {
			/* Error, check errno, take action... */
			switch(errno){
				case EWOULDBLOCK:
					flag = -1;
					break;
					
				case ENOTSOCK:
					return -1;
					break;
					
				case EINTR:
					break;
					
				case ECONNRESET:
				case EINVAL:
				case ENOTCONN:
				case EOPNOTSUPP:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockRecv Udp:[%d] Read Error:[%d]\n", 
						sockId, errno);
				  	return -1;
					break;
			}
		} 
		else if (ret == 0) {
		  	/* Peer closed the socket, finish the close */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, "SockRecv Udp:[%d] Peer Close\n", sockId);
		  	return -1;
		}	
	}

	return -1;	
}

int 	SockRxSel_Udp(int 			sockId, 
						_t_cbentry * 	pCbEntry, 
						int 			timeout)
{
	int 				ret;
	fd_set 		 		vFdSet;
	struct 	timeval 	vSockTv;
	fd_set 		*		pFdSet;
	
	if(sockId == -1){
		return -1;
	}
	
	/* Let's Init Select & TimeOut*/
	pFdSet = &(vFdSet);
	FD_ZERO	(pFdSet);
	FD_SET	(sockId, pFdSet);
	
	vSockTv.tv_sec 	= (timeout/1000);
	vSockTv.tv_usec = (timeout%1000) * 1000 ;

	/* Select */
__SOCKRXSEL_AGAIN_UDP:
	ret = select(sockId+1, pFdSet, NULL, NULL, (struct timeval *)(&vSockTv));

	if((ret > 0) && (FD_ISSET(sockId, pFdSet))){
		/* Let's Consume all the Data */
		SockRx_Udp(sockId, pCbEntry);
	}
	else if(ret == 0){
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_NORMAL, "SockRecv Udp:[%d] Select TimeOut\n", sockId);
		return -1;
	}
	else { 
		switch(errno){
			case EBADF:
				/* Here the FD is Error! */
				return -1;
				break;
				
			case EINTR:
				goto __SOCKRXSEL_AGAIN_UDP;
				break;
				
			case EINVAL:
			case ENOMEM:
			default:
				return -1;
				break;
		}
	}
	return ret;
}


/* -----------------------------------------------------------------------
**	TCP Socket 1
**	Send.
**	Receive 1: Wait till Data Arrive.
**	Receive 2: Wait till Timeout.
**	
*/
#define SYS_TCP_RE_WR 		0X5		/* Write Delay Cnt */
#define SYS_TCP_TO_WR 		0X1		/* Write Delay Time */
#define SYS_TCP_BUF_MAX 	0X10000

int 	SockTx_Tcp(int 				sockId, 				
					unsigned char 	* 	pMsg, 	
					int 				msgLen,
					S_SOCKET_ADDRIN *	pSockAddr)
{
	int 				ret, retry, flag;
	struct msghdr 		ioHead;
	struct iovec  		ioVec[1];

	if((!pSockAddr) || (!pMsg) || (msgLen <= 0) || (sockId == -1)){
		return -1;
	}

	/* IoVec */
	ioVec[0].iov_base 	= pMsg;
	ioVec[0].iov_len 	= msgLen;

	/* IoHead */
	ioHead.msg_flags 	= 0; 		
	ioHead.msg_control 	= NULL;		
	ioHead.msg_controllen= 0;		
	ioHead.msg_iov 		= ioVec;	
	ioHead.msg_iovlen 	= 1;	
	ioHead.msg_name 	= pSockAddr;
	ioHead.msg_namelen 	= sizeof(S_SOCKET_ADDRIN);	

	retry	= 0;
	do{
		flag 	= 0;
		ret 	= sendmsg(sockId, &ioHead, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_UDP_RE_WR){
						retry++;
						SYS_SLEEP(SYS_UDP_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockSend Tcp:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}


int 	SockRx_Tcp(int 			sockId, 
					_t_cbentry * 	pCbEntry)
{
	int 				ret, flag;
	socklen_t			vSockLen;
	S_SOCKET_ADDRIN	vSockAddr;

	unsigned char 		vBuf[SYS_TCP_BUF_MAX];

	if(sockId == -1){
		return -1;
	}

	/* Let's Consume all the Data First */
	flag = 1;
	while(flag == 1){
		#if 0
		SYS_MEMZERO(&vSockAddr, sizeof(vSockAddr));
		#endif
		vSockLen = sizeof(S_SOCKET_ADDRIN);	
		ret=recv(sockId, vBuf, SYS_TCP_BUF_MAX, 0);
		if (ret > 0) {
			/* Data read from the socket */
			if(pCbEntry && (pCbEntry->cbProc)){
				if(pCbEntry->cbProc(pCbEntry->pArg, 
									pCbEntry->lArg, 
									vBuf, ret,
									&vSockAddr) == -1){
					/* We Recv the Left*/
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_DEBUG, "SockRecv Tcp:[%d] CallBack Fail!\n", 
						sockId);
				}
			}
			continue;
		}
		else if (ret == -1) {
			/* Error, check errno, take action... */
			switch(errno){
				case EWOULDBLOCK:
					flag = -1;
					break;
					
				case ENOTSOCK:
					return -1;
					break;
					
				case EINTR:
					break;
					
				case ECONNRESET:
				case EINVAL:
				case ENOTCONN:
				case EOPNOTSUPP:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sock, TRACELVL_ERROR, "SockRecv Tcp:[%d] Read Error:[%d]\n", 
						sockId, errno);
				  	return -1;
					break;
			}
		} 
		else if (ret == 0) {
		  	/* Peer closed the socket, finish the close */
			SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, "SockRecv Tcp:[%d] Peer Close\n", sockId);
		  	return -1;
		}	
	}

	return -1;	
}

int 	SockRxSel_Tcp(int 			sockId, 
						_t_cbentry * 	pCbEntry, 
						int 			timeout)
{
	int 				ret;
	fd_set 		 		vFdSet;
	struct 	timeval 	vSockTv;
	fd_set 		*		pFdSet;
	
	if(sockId == -1){
		return -1;
	}
	
	/* Let's Init Select & TimeOut*/
	pFdSet = &(vFdSet);
	FD_ZERO	(pFdSet);
	FD_SET	(sockId, pFdSet);
	
	vSockTv.tv_sec 	= (timeout/1000);
	vSockTv.tv_usec = (timeout%1000) * 1000 ;

	/* Select */
__SOCKRXSEL_AGAIN_TCP:
	ret = select(sockId+1, pFdSet, NULL, NULL, (struct timeval *)(&vSockTv));

	if((ret > 0) && (FD_ISSET(sockId, pFdSet))){
		/* Let's Consume all the Data */
		ret = SockRx_Tcp(sockId, pCbEntry);
	}
	else if(ret == 0){
		SYS_TRACE(_gTraceLvl_Sock, TRACELVL_WARNING, "SockRecv Tcp:[%d] Select TimeOut\n", sockId);
		return -1;
	}
	else { 
		switch(errno){
			case EBADF:
				/* Here the FD is Error! */
				return -1;
				break;
				
			case EINTR:
				goto __SOCKRXSEL_AGAIN_TCP;
				break;
				
			case EINVAL:
			case ENOMEM:
			default:
				return -1;
				break;
		}
	}
	return ret;
}


/* -----------------------------------------------------------------------
**	Unix Socket
**	Send.
**	Receive 1: Wait till Data Arrive.
**	Receive 2: Wait till Timeout.
**
*/
#define SYS_UNIX_RE_WR 		0X5		/* Write Delay Cnt */
#define SYS_UNIX_TO_WR 		0X1		/* Write Delay Time */
#define SYS_UNIX_BUF_MAX 	0X10000

int 	SockTx_Unix(int sockId, unsigned char * pMsg,  int msgLen, S_SOCKET_ADDRUX * pSockAddr)
{
	int 				ret, retry, flag;
	struct msghdr 		ioHead;
	struct iovec  		ioVec[1];

	if((!pSockAddr) || (!pMsg) || (msgLen <= 0) || (sockId == -1)){
		return -1;
	}

	/* IoVec */
	ioVec[0].iov_base 	= pMsg;
	ioVec[0].iov_len 	= msgLen;

	/* IoHead */
	ioHead.msg_flags 	= 0; 		
	ioHead.msg_control 	= NULL;		
	ioHead.msg_controllen= 0;		
	ioHead.msg_iov 		= ioVec;	
	ioHead.msg_iovlen 	= 1;	
	ioHead.msg_name 	= pSockAddr;
	ioHead.msg_namelen 	= sizeof(S_SOCKET_ADDRUX);	

	retry	= 0;
	do{
		flag 	= 0;
		ret 	= sendmsg(sockId, &ioHead, 0);
		if(ret == -1){
			switch(errno){
				case EWOULDBLOCK:
				case EINTR:
					/* Here We Delay for a While */
					if(retry < SYS_UNIX_RE_WR){
						retry++;
						SYS_SLEEP(SYS_UNIX_TO_WR);
						flag = 1;
					}
					break;

				case EAFNOSUPPORT:
				case EBADF:
				case ENOTCONN:
				case ENOTSOCK:
				case EOPNOTSUPP:
				case EPIPE:	
				case EIO:
				case ELOOP:
				case ENAMETOOLONG:
				case ENOENT:
				case ENOTDIR:
				case EACCES:
				case EDESTADDRREQ:
				case EHOSTUNREACH:
				case EINVAL:
				case EISCONN:
					return -1;
					break;

				case ENETDOWN:
				case ENETUNREACH:
				case ECONNRESET:
				case ECONNREFUSED:
					/* Net Down | UnReach | Close ? */
					/* Net UnReach */
					return -1;
					break;
					
				case EMSGSIZE:
				case ENOBUFS:
				case ENOMEM:
					/* Size Memory ? */
					return -1;
					break;
					
				default:
					SYS_TRACE(_gTraceLvl_Sock,  TRACELVL_ERROR, "SockSend Unix:[%d] Err:[%d]\n", sockId, errno);
					return -1;
					break;
			}
		}
	}while(flag == 1);

	return 0;
}

int 	SockRx_Unix(int sockId, _t_cbentry * pCbEntry)
{
	int 				ret, flag;
	socklen_t			vSockLen;

	S_SOCKET_ADDRUX	vSockAddr;
	unsigned char 		vBuf[SYS_UNIX_BUF_MAX];

	if(sockId == -1){
		return -1;
	}

	/* Let's Consume all the Data First */
	flag = 1;
	while(flag == 1){
		#if 0
		SYS_MEMZERO(&vSockAddr, sizeof(vSockAddr));
		#endif
		vSockLen = sizeof(S_SOCKET_ADDRUX);
		ret=recvfrom(sockId, vBuf, SYS_UNIX_BUF_MAX, 0, 
					(struct  sockaddr *)(&vSockAddr), &vSockLen);
		if (ret > 0) {
			/* Data read from the socket */
			if(pCbEntry && (pCbEntry->cbProc)){
				if(pCbEntry->cbProc(pCbEntry->pArg, 
									pCbEntry->lArg, 
									vBuf, ret,
									&vSockAddr) == -1){
					/* We Recv the Left*/
					SYS_TRACE(_gTraceLvl_Sock,  TRACELVL_WARNING,  "SockRecv Unix:[%d] CallBack Fail!\n", 
						sockId);
				}
			}
			continue;
		}
		else if (ret == -1) {
			/* Error, check errno, take action... */
			switch(errno){
				case EWOULDBLOCK:
					flag = -1;
					break;
					
				case ENOTSOCK:
					return -1;
					break;
					
				case EINTR:
					break;
					
				case ECONNRESET:
				case EINVAL:
				case ENOTCONN:
				case EOPNOTSUPP:
				case ETIMEDOUT:
				default:
					SYS_TRACE(_gTraceLvl_Sock,  TRACELVL_ERROR,  "SockRecv Unix:[%d] Read Error:[%d]\n", 
						sockId, errno);
				  	return -1;
					break;
			}
		} 
		else if (ret == 0) {
		  	/* Peer closed the socket, finish the close */
			SYS_TRACE(_gTraceLvl_Sock,  TRACELVL_WARNING,  "SockRecv Unix:[%d] Peer Close\n", sockId);
		  	return -1;
		}	
	}

	return -1;	
}

int 	SockRxSel_Unix(int sockId, _t_cbentry * pCbEntry, int timeout)
{
	int 				ret;
	struct 	timeval 	vSockTv;
	fd_set 		 		vFdSet;
	fd_set 		*		pFdSet;
	
	if(sockId == -1){
		return -1;
	}
	
	/* Let's Init Select & TimeOut*/
	pFdSet = &(vFdSet);
	FD_ZERO	(pFdSet);
	FD_SET	(sockId, pFdSet);
	
	vSockTv.tv_sec 	= (timeout/1000);
	vSockTv.tv_usec = (timeout%1000) * 1000 ;

	/* Select */
__SOCKRXSEL_AGAIN_UNIX:
	ret = select(sockId+1, pFdSet, NULL, NULL, (struct timeval *)(&vSockTv) );

	if((ret > 0) && (FD_ISSET(sockId, pFdSet ))){
		/* Let's Consume all the Data */
		SockRx_Unix(sockId, pCbEntry);
	}
	else if(ret == 0){
		SYS_TRACE(_gTraceLvl_Sock,  TRACELVL_NORMAL,  "SockRecv Unix:[%d] Select TimeOut\n", sockId);
		return -1;
	}
	else { 
		switch(errno){
			case EBADF:
				/* Here the FD is Error! */
				return -1;
				break;
				
			case EINTR:
				goto __SOCKRXSEL_AGAIN_UNIX;
				break;
				
			case EINVAL:
			case ENOMEM:
			default:
				return -1;
				break;
		}
	}
	return ret;
}

